#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <sys/poll.h>
#include "Sock.hpp"
#include "Err.hpp"
#include "Log.hpp"

namespace Yohifo
{
#define DEFAULT_EVENT 0

    // 多路转接服务器
    static const uint16_t gport = 8888;

    // 第三方数组，维护 fd
    // typedef int type_t;
    typedef pollfd type_t;

    int N = (sizeof(fd_set) * 8);

    static const int defaultFd = -1;

    class SelectServer
    {
    public:
        SelectServer(const uint16_t &port = gport)
            : port_(port)
            ,fdarray_ (nullptr)
        {
            logMessage(Debug, "port: %d", port_);
        }

        ~SelectServer()
        {
            listen_sock_.Close();

            if(fdarray_)
                delete[] fdarray_;
        }

        void InitServer()
        {
            // 创建套接字、绑定、监听
            listen_sock_.Socket();
            listen_sock_.Bind(port_);
            listen_sock_.Listen();

            //开辟空间大小
            fdarray_ = new type_t[N];

            for (int i = 0; i < N; i++)
            {
                if(i == 0)
                {
                    fdarray_[i].fd = listen_sock_.getFd(); // 这个是固定的
                    fdarray_[i].events = POLLIN;    //读事件
                    fdarray_[i].revents = DEFAULT_EVENT;
                }
                else
                {
                    fdarray_[i].fd = defaultFd;
                    fdarray_[i].events = DEFAULT_EVENT;    //默认事件
                    fdarray_[i].revents = DEFAULT_EVENT;
                }
            }

            logMessage(Debug, "socket、bind、listen Success");
        }

        void Accepter()
        {
            // listen 事件已响应，此时 accept 是不会被阻塞的
            std::string clientIP;
            uint16_t clientPort;
            int sock = listen_sock_.Accept(&clientIP, &clientPort);
            if (sock < 0)
                return;

            // 将收到的 sock 存入 fdarray 中
            int pos;
            for (pos = 1; pos < N; pos++)
                if (fdarray_[pos].fd == defaultFd)
                    break;
            if (pos == N)
            {
                // fdarray 满了
                //扩容
                type_t* newSpace = new type_t[N * 2];

                for(int i = 0; i < N; i++)
                    newSpace[i] = fdarray_[i];
                
                std::swap(newSpace, fdarray_);
                delete[] newSpace;
                N *= 2;

                logMessage(Info, "扩容成功: %d", N);
            }
            else
            {
                // 存入 fdarray
                fdarray_[pos].fd = sock;
                fdarray_[pos].events = (POLLIN | POLLOUT);

                DebugPrint();
            }
        }

        void Recver(int i)
        {
            // 已经响应的 fd，此时可以直接读取，并且保证此时读取是一定不会被阻塞的
            char buff[N];

            int n = recv(fdarray_[i].fd, buff, sizeof(buff) - 1, 0);
            if (n > 0)
            {
                buff[n - 1] = 0; // 去掉 换行符
                std::cout << "client #: " << buff << std::endl;

                // 将进行数据回响
                std::string msg = buff;
                msg = "[server echo]: " + msg + "\n";

                send(fdarray_[i].fd, msg.c_str(), msg.size(), 0);
            }
            else
            {
                if (n == 0)
                {
                    // 读取到末尾而结束
                    logMessage(Debug, "Recv end");
                }
                else
                {
                    // 读取失败
                    logMessage(Warning, "Recv fail");
                }

                // 关闭文件描述符、清理 fdarray
                int fd = fdarray_[i].fd;
                close(fdarray_[i].fd);
                fdarray_[i].fd = defaultFd;
                fdarray_[i].events = DEFAULT_EVENT;
                fdarray_[i].revents = DEFAULT_EVENT;

                DebugPrint();

                logMessage(Debug, "Close %d Success", fd);
            }
        }

        void HandlerEvent()
        {
           for (int i = 0; i < N; i++)
            {
                if (fdarray_[i].fd == defaultFd)
                    continue;

                if(fdarray_[i].revents & POLLIN)
                {
                    if(fdarray_[i].fd == listen_sock_.getFd())
                        Accepter();
                    else
                        Recver(i);
                }
                else if(fdarray_[i].revents & POLLOUT)
                {
                    //TODO
                }
            }
        }

        void StartServer()
        {
            // 在获取链接之前，需要将 fd 保存至 fd_set 中
            int timeout = -1;
            while (true)
            {
                int n = poll(fdarray_, N, timeout);
                switch (n)
                {
                case 0:
                    logMessage(Debug, "timeout, %d %s", errno, strerror(errno));
                    break;
                case -1:
                    logMessage(Warning, "%d %s", errno, strerror(errno));
                    break;
                default:
                    logMessage(Info, "有一个事件就绪了 %d", n);
                    HandlerEvent();
                    break;
                }
            }
        }

        void DebugPrint()
        {
            // 打印 fdarray 信息
            std::cout << "==================================" << std::endl;
            std::cout << "fdarray: ";
            for (int i = 0; i < N; i++)
                if (fdarray_[i].fd != defaultFd)
                    std::cout << fdarray_[i].fd << " ";
            std::cout << std::endl
                      << "==================================" << std::endl;
        }

    private:
        Sock listen_sock_;
        uint16_t port_;
        type_t *fdarray_;
    };
}